﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
#include <QDateTime>
#include <QIntValidator>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 初始化串口对象
    serialPort = new QSerialPort(this);



    // 初始化定时器
    dataTimer = new QTimer(this);
    connect(dataTimer, &QTimer::timeout, this, &MainWindow::updateSensorData);

    // 设置默认地址
    currentAddress = 0xFF;
    ui->addressLineEdit->setText("FF");
    ui->addressLineEdit->setValidator(new QIntValidator(0, 255, this));

    // 初始化数据标签
    dataLabels = {
        ui->temperatureValue, ui->humidityValue, ui->pressureValue,
        ui->windSpeedValue, ui->windDirectionValue, ui->rainfallValue,
        ui->radiationValue, ui->illuminanceValue, ui->sunshineValue,
        ui->dewPointValue, ui->et0Value
    };

    // 初始化图表
    temperatureChart = new QChart();
    temperatureSeries = new QLineSeries();
    temperatureSeries->setName("Temperature (°C)");

    temperatureChart->addSeries(temperatureSeries);
    temperatureChart->setTitle("Temperature History");
    temperatureChart->legend()->hide();
    //设置图标
    axisX = new QValueAxis();
    axisX->setTitleText("Time (s)");
    axisX->setLabelFormat("%d");
    axisX->setRange(0, 60);
    temperatureChart->addAxis(axisX, Qt::AlignBottom);
    temperatureSeries->attachAxis(axisX);

    axisY = new QValueAxis();
    axisY->setTitleText("Temperature (°C)");
    axisY->setRange(-10, 50);
    temperatureChart->addAxis(axisY, Qt::AlignLeft);
    temperatureSeries->attachAxis(axisY);

    chartView = new QChartView(temperatureChart);
    chartView->setRenderHint(QPainter::Antialiasing);
    ui->chartLayout->addWidget(chartView);

    // 设置初始状态
    updateStatus("Ready to connect", false);
    ui->disconnectButton->setEnabled(false);
    ui->intervalSlider->setValue(5);
    ui->intervalLabel->setText("Update interval: 5s");

    // 初始化历史数据
    temperatureHistory.fill(0.0, 60);
    humidityHistory.fill(0.0, 60);
    pressureHistory.fill(0.0, 60);
    windSpeedHistory.fill(0.0, 60);

    //初始化串口
    ui->portComboBox->clear();
    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();

    if (ports.isEmpty()){
                ui->portComboBox->addItem("未找到可用串口");
                ui->connectButton->setEnabled(false);
                return;
    }
    foreach(const QSerialPortInfo &info, ports) {
               QString displayText = QString("%1")
                   .arg(info.portName());
               ui->portComboBox->addItem(displayText, info.portName());
    }

}

MainWindow::~MainWindow()
{
    delete ui;
    if (serialPort->isOpen()) {
        serialPort->close();
    }
}

void MainWindow::on_connectButton_clicked()
{
    QString portName = ui->portComboBox->currentText();



    serialPort->setPortName(portName);
    serialPort->setBaudRate(QSerialPort::Baud9600);
    serialPort->setDataBits(QSerialPort::Data8);
    serialPort->setParity(QSerialPort::NoParity);
    serialPort->setStopBits(QSerialPort::OneStop);
    serialPort->setFlowControl(QSerialPort::NoFlowControl);

    if (!serialPort->open(QIODevice::ReadWrite)) {
        updateStatus("Failed to open port: " + serialPort->errorString(), true);
        return;
    }

    // 读取设备地址
    currentAddress = readDeviceAddress();

      if (!currentAddress) {
           updateStatus("Failed to read device address", true);
       } else {
           ui->addressLineEdit->setText(QString::number(currentAddress, 16).toUpper());
           updateStatus("Connected to sensor. Address: 0x" + QString::number(currentAddress, 16).toUpper());
       }

//    if (currentAddress == 0xFF) {
//        updateStatus("Failed to read device address", true);
//    } else {
//        ui->addressLineEdit->setText(QString::number(currentAddress, 16).toUpper());
//        updateStatus("Connected to sensor. Address: 0x" + QString::number(currentAddress, 16).toUpper());
//    }

    ui->connectButton->setEnabled(false);
    ui->disconnectButton->setEnabled(true);

    // 开始定时读取数据
    dataTimer->start(ui->intervalSlider->value() * 1000);
}

void MainWindow::on_disconnectButton_clicked()
{
    dataTimer->stop();
    if (serialPort->isOpen()) {
        serialPort->close();
    }
    ui->connectButton->setEnabled(true);
    ui->disconnectButton->setEnabled(false);
    updateStatus("Disconnected");
}

void MainWindow::updateSensorData()
{
    QMap<QString, double> sensorData = readAllSensors(currentAddress);

    if (!sensorData.isEmpty()) {
        updateDataDisplay(sensorData);

        // 更新历史数据
        static int timeCounter = 0;
        timeCounter++;

        temperatureHistory.pop_back();
        temperatureHistory.prepend(sensorData["temperature"]);

        humidityHistory.pop_back();
        humidityHistory.prepend(sensorData["humidity"]);

        pressureHistory.pop_back();
        pressureHistory.prepend(sensorData["pressure"]);

        windSpeedHistory.pop_back();
        windSpeedHistory.prepend(sensorData["wind_speed"]);

        // 更新图表
        updateChart();

        updateStatus("Data updated: " + QDateTime::currentDateTime().toString("hh:mm:ss"));
    } else {
        updateStatus("Failed to read sensor data", true);
    }
}

void MainWindow::on_intervalSlider_valueChanged(int value)
{
    ui->intervalLabel->setText("Update interval: " + QString::number(value) + "s");
    if (dataTimer->isActive()) {
        dataTimer->stop();
        dataTimer->start(value * 1000);
    }
}

void MainWindow::on_readAddressButton_clicked()
{
    if (!serialPort->isOpen()) {
        updateStatus("Serial port not connected", true);
        return;
    }

    quint8 addr = readDeviceAddress();

    //修改第二处！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
        currentAddress = addr;
        ui->addressLineEdit->setText(QString::number(addr, 16).toUpper());
        updateStatus("Device address: 0x" + QString::number(addr, 16).toUpper());

//    if (addr != 0xFF) {
//        currentAddress = addr;
//        ui->addressLineEdit->setText(QString::number(addr, 16).toUpper());
//        updateStatus("Device address: 0x" + QString::number(addr, 16).toUpper());
//    } else {
//        updateStatus("Failed to read device address", true);
//    }
}

void MainWindow::on_changeAddressButton_clicked()
{
    if (!serialPort->isOpen()) {
        updateStatus("Serial port not connected", true);
        return;
    }

    bool ok;
    quint8 newAddr = ui->addressLineEdit->text().toInt(&ok, 16);

    if (!ok || newAddr < 1 || newAddr > 247) {
        updateStatus("Invalid address (1-247 or 0x01-0xF7)", true);
        return;
    }

    if (changeDeviceAddress(newAddr)) {
        currentAddress = newAddr;
        updateStatus("Address changed to 0x" + QString::number(newAddr, 16).toUpper());
    } else {
        updateStatus("Failed to change address", true);
    }
}

quint16 MainWindow::calculateCRC(const QByteArray &data)
{
    quint16 crc = 0xFFFF;
    for (int pos = 0; pos < data.size(); pos++) {
        crc ^= (quint8)data[pos];
        for (int i = 8; i != 0; i--) {
            if ((crc & 0x0001) != 0) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

QByteArray MainWindow::sendCommand(const QByteArray &command, int expectedLength, int timeout)
{
    if (!serialPort->isOpen()) {
        qWarning() << "Serial port is not open";
        return QByteArray();
    }

    // 计算CRC并附加到命令
    quint16 crc = calculateCRC(command);
    QByteArray fullCommand = command;
    fullCommand.append(static_cast<char>(crc & 0xFF)); // 低字节在前
    fullCommand.append(static_cast<char>((crc >> 8) & 0xFF));

    // 发送命令
    serialPort->write(fullCommand);
    if (!serialPort->waitForBytesWritten(timeout)) {
        qWarning() << "Write operation timed out";
        return QByteArray();
    }

    // 等待响应
    QByteArray response;
    while (response.size() < expectedLength && serialPort->waitForReadyRead(timeout)) {
        response += serialPort->readAll();
    }

    // 验证响应长度
    if (response.size() < 4) { // 最小响应长度（地址+功能码+CRC）
        qWarning() << "Response too short:" << response.toHex();
        return QByteArray();
    }

    // 验证CRC
    QByteArray responseWithoutCRC = response.left(response.size() - 2);
    quint16 receivedCRC = (static_cast<quint8>(response.at(response.size()-1)) << 8) |
                          static_cast<quint8>(response.at(response.size()-2));

    if (calculateCRC(responseWithoutCRC) != receivedCRC) {
        qWarning() << "CRC mismatch";
        return QByteArray();
    }

    return responseWithoutCRC;
}

QMap<QString, double> MainWindow::readAllSensors(quint8 address)
{
    QMap<QString, double> result;

    // 构建命令：地址 + 功能码03 + 起始地址00 01 + 寄存器数量00 0B
    QByteArray command;
    command.append(static_cast<char>(address));
    command.append(0x03);
    command.append(static_cast<char>(0x00));
    command.append(static_cast<char>(0x01)); // 起始地址0x0001
    command.append(static_cast<char>(0x00));
    command.append(static_cast<char>(0x0B)); // 11个寄存器

    QByteArray response = sendCommand(command, 27); // 期望响应长度：27字节
    if (response.size() != 25) { // 1(地址)+1(功能码)+1(字节数)+22(数据)+2（CRC校验）=25字节，去掉CRC2字节，所以是25字节
        qWarning() << "Invalid response length:" << response.size() << "expected 25";
        return result;
    }

    // 解析数据
    for (int i = 0; i < 11; i++) {
        int pos = 3 + i * 2;
        quint16 value = (static_cast<quint8>(response.at(pos)) << 8 |
                        static_cast<quint8>(response.at(pos+1)));

        double convertedValue = 0.0;



        switch (i) {
        case 0: // 温度
            convertedValue = value / 100.0 - 40;
            result["temperature"] = convertedValue;
            break;
        case 1: // 湿度
            convertedValue = value / 100.0;
            result["humidity"] = convertedValue;
            break;
        case 2: // 气压
            convertedValue = value / 10.0;
            result["pressure"] = convertedValue;
            break;
        case 3: // 风速
            convertedValue = value / 100.0;
            result["wind_speed"] = convertedValue;
            break;
        case 4: // 风向
            convertedValue = value / 10.0;
            result["wind_direction"] = convertedValue;
            break;
        case 5: // 雨量
            convertedValue = value / 10.0;
            result["rainfall"] = convertedValue;
            break;
        case 6: // 辐射
            convertedValue = value;
            result["radiation"] = convertedValue;
            break;
        case 7: // 光照
            convertedValue = value / 100.0;
            result["illuminance"] = convertedValue;
            break;
        case 8: // 日照时数
            convertedValue = value / 10.0;
            result["sunshine_hours"] = convertedValue;
            break;
        case 9: // 露点温度
            convertedValue = value / 10.0;
            result["dew_point"] = convertedValue;
            break;
        case 10: // ET0
            convertedValue = value / 10.0;
            result["et0"] = convertedValue;
            break;
        }
    }

    return result;
}

quint8 MainWindow::readDeviceAddress()
{
    QByteArray command;
    command.append(static_cast<char>(0x00)); // 广播地址
    command.append(0x03); // 功能码
    command.append(static_cast<char>(0x00)); // 寄存器地址高字节
    command.append(static_cast<char>(0x00)); // 寄存器地址低字节
    command.append(static_cast<char>(0x00)); // 寄存器数量高字节
    command.append(static_cast<char>(0x01)); // 寄存器数量低字节

    QByteArray response = sendCommand(command, 7); // 期望响应长度：7字节
    if (response.size() != 5) { // 1(地址)+1(功能码)+1(字节数)+2(数据)=5字节
        qWarning() << "Invalid response length for address read:" << response.size();
        return 0xFF; // 返回默认地址表示失败
    }

    // 解析地址
    quint16 address = (static_cast<quint8>(response.at(3)) << 8 |
                      static_cast<quint8>(response.at(4)));
    return static_cast<quint8>(address);
}

bool MainWindow::changeDeviceAddress(quint8 newAddress)
{
    QByteArray command;
    command.append(static_cast<char>(0x00)); // 广播地址
    command.append(0x06); // 功能码
    command.append(static_cast<char>(0x00)); // 寄存器地址高字节
    command.append(static_cast<char>(0x00)); // 寄存器地址低字节
    command.append(static_cast<char>(0x00)); // 新地址高字节
    command.append(static_cast<char>(newAddress)); // 新地址低字节

    QByteArray response = sendCommand(command, 8); // 期望响应长度：8字节
    if (response.size() != 6) { // 1(地址)+1(功能码)+2(寄存器地址)+2(数据)=6字节
        qWarning() << "Invalid response length for address change:" << response.size();
        return false;
    }

    // 验证响应是否与发送的命令相同
    return response == command;
}

void MainWindow::updateDataDisplay(const QMap<QString, double> &data)
{
    // 设置数值显示
    dataLabels[0]->setText(QString::number(data["temperature"], 'f', 1) + " °C");
    dataLabels[1]->setText(QString::number(data["humidity"], 'f', 1) + " %");
    dataLabels[2]->setText(QString::number(data["pressure"], 'f', 1) + " hPa");
    dataLabels[3]->setText(QString::number(data["wind_speed"], 'f', 1) + " m/s");
    dataLabels[4]->setText(QString::number(data["wind_direction"], 'f', 1) + " °");
    dataLabels[5]->setText(QString::number(data["rainfall"], 'f', 1) + " mm");
    dataLabels[6]->setText(QString::number(data["radiation"], 'f', 0) + " W/㎡");
    dataLabels[7]->setText(QString::number(data["illuminance"], 'f', 1) + " lux");
    dataLabels[8]->setText(QString::number(data["sunshine_hours"], 'f', 1) + " h");
    dataLabels[9]->setText(QString::number(data["dew_point"], 'f', 1) + " °C");
    dataLabels[10]->setText(QString::number(data["et0"], 'f', 1) + " mm");

    // 更新环境指示器
    double temp = data["temperature"];
    if (temp < 0) {
        ui->tempIndicator->setStyleSheet("background-color: blue; border-radius: 10px;");
    } else if (temp < 15) {
        ui->tempIndicator->setStyleSheet("background-color: lightblue; border-radius: 10px;");
    } else if (temp < 25) {
        ui->tempIndicator->setStyleSheet("background-color: green; border-radius: 10px;");
    } else if (temp < 35) {
        ui->tempIndicator->setStyleSheet("background-color: orange; border-radius: 10px;");
    } else {
        ui->tempIndicator->setStyleSheet("background-color: red; border-radius: 10px;");
    }

    double humidity = data["humidity"];
    if (humidity < 30) {
        ui->humidityIndicator->setStyleSheet("background-color: #e0e0e0; border-radius: 10px;");
    } else if (humidity < 60) {
        ui->humidityIndicator->setStyleSheet("background-color: #90ee90; border-radius: 10px;");
    } else {
        ui->humidityIndicator->setStyleSheet("background-color: #87cefa; border-radius: 10px;");
    }
}

void MainWindow::updateChart()
{
    temperatureSeries->clear();

    for (int i = 0; i < temperatureHistory.size(); i++) {
        temperatureSeries->append(i, temperatureHistory[i]);
    }

    // 更新图表范围
    double minTemp = *std::min_element(temperatureHistory.begin(), temperatureHistory.end());
    double maxTemp = *std::max_element(temperatureHistory.begin(), temperatureHistory.end());

    // 添加一些余量
    minTemp = qFloor(minTemp) - 1;
    maxTemp = qCeil(maxTemp) + 1;

    axisY->setRange(minTemp, maxTemp);

    // 重新渲染图表
    chartView->update();
}

void MainWindow::updateStatus(const QString &message, bool isError)
{
    if (isError) {
        ui->statusBar->setStyleSheet("color: red;");
    } else {
        ui->statusBar->setStyleSheet("color: black;");
    }
    ui->statusBar->showMessage(message);
}

